package cc.rengu.igas.opms.core.service.trans.common;

import cc.rengu.igas.opms.common.constant.OpmsParamConstant;
import cc.rengu.igas.opms.common.enums.RespCodeEnum;
import cc.rengu.igas.opms.core.service.base.ManageService;
import cc.rengu.igas.opms.facade.request.ResetPayPasswdRequest;
import cc.rengu.igas.opms.facade.response.ResetPayPasswdResponse;
import cc.rengu.igas.share.common.constant.UserSessionConstant;
import cc.rengu.igas.share.core.model.UserInfo;
import cc.rengu.igas.share.core.realize.UserService;
import cc.rengu.igas.share.core.realize.impl.UserServiceImpl;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.SignAcctInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.SignAcctInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.SignAcctInfo;
import cc.rengu.oltp.service.common.enums.PinTypeEnum;
import cc.rengu.oltp.service.common.enums.SmsTypeEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.model.PasswordInfo;
import cc.rengu.oltp.service.realize.SafeKeyBoardService;
import cc.rengu.oltp.service.realize.SensitiveInfoService;
import cc.rengu.oltp.service.realize.SmsService;
import cc.rengu.oltp.service.realize.impl.SafeKeyBoardServiceImpl;
import cc.rengu.oltp.service.realize.impl.SensitiveInfoServiceImpl;
import cc.rengu.oltp.service.realize.impl.SmsServiceImpl;
import cc.rengu.oltp.utility.util.*;

import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 重置支付密码
 * Created by fuyp on 2020/4/23.
 * modify by wangcheng 2021-09-13
 */
public class ResetPayPasswdService extends ManageService {
    @Override
    protected Object bizBeforeCust() throws Exception {
        ResetPayPasswdRequest resetPayPasswdRequest = new ResetPayPasswdRequest();
        ConvertUtil.convertOutput(resetPayPasswdRequest);
        return resetPayPasswdRequest;
    }

    @Override
    protected BizResponse bizProcessCust(Object request) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        BizResponse<ResetPayPasswdResponse> bizResponse = new BizResponse<>();
        bizResponse.setRspSysId(AppParamConstant.IGAS);
        ResetPayPasswdResponse resetPayPasswdResponse = new ResetPayPasswdResponse();
        ResetPayPasswdRequest resetPayPasswdRequest = (ResetPayPasswdRequest) request;
        String instId = resetPayPasswdRequest.getHeader().getInstId();
        String userId = resetPayPasswdRequest.getUserId();
        String txnMode = resetPayPasswdRequest.getTxnMode();
        String payAcctNo = resetPayPasswdRequest.getPayAcctNo();

        //检查会话
        UserService userService = new UserServiceImpl();
        UserInfo userInfo = userService.getUserInfo(instId, userId, resetPayPasswdRequest.getHeader().getSession());
        if (null == userInfo) {
            rglog.error("获取用户信息失败!");
            throw new BizException(RespCodeEnum.USER_NOT_LOGIN_OR_SESSION_IS_EXPIRED.getRespCode(), RespCodeEnum.USER_NOT_LOGIN_OR_SESSION_IS_EXPIRED.getRespDesc());
        }
        //判断上送的手机号是否为脱敏后的手机号，若是则恢复成未脱敏的手机号
        if (!StringUtil.isEmptyOrNull(resetPayPasswdRequest.getPhoneNo())) {
            Pattern pattern = Pattern.compile("^1[0-9]{10}$");
            Matcher matcher = pattern.matcher(resetPayPasswdRequest.getPhoneNo());
            if (!matcher.matches()) {
                rglog.info("当前手机号为脱敏后的手机号，需转换成明文!");
                SensitiveInfoService sensitiveInfoService = new SensitiveInfoServiceImpl();
                Map<String, String> keyValueMap = sensitiveInfoService.recovery("phoneNo", resetPayPasswdRequest.getPhoneNo(), resetPayPasswdRequest.getHeader().getSession());
                String phoneNo = keyValueMap.get(resetPayPasswdRequest.getPhoneNo());
                resetPayPasswdRequest.setPhoneNo(phoneNo);
            }
        }
        if (!StringUtil.isEmptyOrNull(resetPayPasswdRequest.getPayAcctNo())){
            Pattern pattern = Pattern.compile("[0-9]*");
            Matcher matcher = pattern.matcher(resetPayPasswdRequest.getPayAcctNo());
            if (!matcher.matches()) {
                rglog.info("当前支付账号为脱敏后的支付账号号，需转换成明文!");
                SensitiveInfoService sensitiveInfoService = new SensitiveInfoServiceImpl();
                Map<String, String> keyValueMap = sensitiveInfoService.recovery("payAcctNo", resetPayPasswdRequest.getPayAcctNo(), resetPayPasswdRequest.getHeader().getSession());
                payAcctNo = keyValueMap.get(resetPayPasswdRequest.getPayAcctNo());
                resetPayPasswdRequest.setPayAcctNo(payAcctNo);
            }
        }
        //获取用户主体和签约主体 在首次签约并支付后设置支付密码session中不存在UserInst和SignInst需要根据商户号进行查询
        String signInst = userService.getUserSignInst();
        //交易类别 00-身份验证
        if ("00".equals(txnMode)) {
            //查询短信验证码表（T_P_SMS_INFO）,校验短信验证码字段（authCode）,修改密码与设置密码使用短信模板不一致需分开校验短信验证码
            SmsService smsService = new SmsServiceImpl();
            if ("00".equals(resetPayPasswdRequest.getHeader().getBizType())) {
                rglog.debug("重置支付密码校验短信验证码");
                smsService.verifySmsCode(instId, SmsTypeEnum.RESET_PASSWORD.getSmsType(), resetPayPasswdRequest.getSmsCode(), resetPayPasswdRequest.getSmsVerifySeqNum());
            } else if ("01".equals(resetPayPasswdRequest.getHeader().getBizType())) {
                rglog.debug("设置支付密码校验短信验证码");
                smsService.verifySmsCode(instId, SmsTypeEnum.SET_PASSWORD.getSmsType(), resetPayPasswdRequest.getSmsCode(), resetPayPasswdRequest.getSmsVerifySeqNum());
            } else {
                rglog.info("不识别的业务分类，bizType:<{}>", resetPayPasswdRequest.getHeader().getBizType());
                throw new BizException(RespCodeEnum.PARAM_ERROR.getRespCode(), RespCodeEnum.PARAM_ERROR.getRespDesc());
            }
            //查询用户签约信息表（T_P_SIGN_ACCT_INFO）获取身份验证交易结果状态
            SignAcctInfoMapper signAcctInfoMapper = new SignAcctInfoMapperImpl();
            List<SignAcctInfo> signAcctInfos = signAcctInfoMapper.selectSignAcctInfoBySignAcctNo(instId, payAcctNo);
            if (null == signAcctInfos || signAcctInfos.isEmpty()) {
                rglog.info("用户不存在签约信息，instId:<{}>,signInst:<{}>,signAcctNo:<{}>", instId, signInst, payAcctNo);
                throw new BizException(RespCodeEnum.GET_SIGN_INFO_ERROR.getRespCode(), RespCodeEnum.GET_SIGN_INFO_ERROR.getRespDesc());
            } else {
                signAcctInfos = signAcctInfos.stream().filter(item -> item.getSignInst().equals(signInst) &&
                        item.getSignStatus().equals(AppParamConstant.YES)).collect(Collectors.toList());
            }
            //筛选当前证件做的签约交易
            List<SignAcctInfo> certTypeSignAcctInfos = signAcctInfos.stream().filter(item -> resetPayPasswdRequest.getCertType().equals(item.getCertType())).collect(Collectors.toList());
            if (certTypeSignAcctInfos.isEmpty()) {
                rglog.info("用户未使用当前证件做签约交易,requestCertType:<{}>", resetPayPasswdRequest.getCertType());
                throw new BizException(RespCodeEnum.USER_INFO_MISMATCH.getRespCode(), RespCodeEnum.USER_INFO_MISMATCH.getRespDesc());
            }
            //校验上送的证件号是否一致
            SignAcctInfo signAcctInfo = certTypeSignAcctInfos.get(0);
            if (!signAcctInfo.getCertNo().equals(resetPayPasswdRequest.getCertNo())) {
                rglog.info("用户证件信息不匹配,exitCertType:<{}>,exitCertNo:<{}>,reqCertType:<{}>,reqCertNo:<{}>",
                        signAcctInfo.getCertType(), signAcctInfo.getCertNo(), resetPayPasswdRequest.getCertType(), resetPayPasswdRequest.getCertNo());
                throw new BizException(RespCodeEnum.USER_INFO_MISMATCH.getRespCode(), RespCodeEnum.USER_INFO_MISMATCH.getRespDesc());
            }
            //身份验证通过后，需要把认证token存在会话的缓存数据中，并返回token.使用系统流水号作为authToken的值
            String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
            userService.setUserSessionValue(UserSessionConstant.IDENTITY_VERIFY_SEQ_NUM, sysSeqNum);
            resetPayPasswdResponse.setAuthToken(sysSeqNum);
            bizResponse.setResult(resetPayPasswdResponse);
            bizResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
            bizResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
            return bizResponse;
        }
        //交易类别 01-设置密码
        else if ("01".equals(txnMode)) {
            //检测上送的手机号和用户的签约手机号是否一致
            if (!userInfo.getMobileNo().equals(resetPayPasswdRequest.getPhoneNo())) {
                rglog.info("上送手机号和用户签约手机号不一致，userMobile:<{}>, reqeustMobile:<{}>",
                        userInfo.getMobileNo(), resetPayPasswdRequest.getPhoneNo());
                throw new BizException(RespCodeEnum.MOBILE_DIFERENT.getRespCode(), RespCodeEnum.MOBILE_DIFERENT.getRespDesc());
            }
            //校验验证码流水号字段，根据session获取会话对象数据，从session对象获取authToken无缓存数据则验证失败；有缓存数据验证通过。验证通过后，设置value为空
            String authTokenValue = userService.getUserSessionValue(UserSessionConstant.IDENTITY_VERIFY_SEQ_NUM);
            if (null == authTokenValue || !authTokenValue.equals(resetPayPasswdRequest.getAuthToken())) {
                rglog.info("授权信息不存在或授权信息不正确，requestAuthToken:<{}>,sessionAuthToken:<{}>",
                        resetPayPasswdRequest.getAuthToken(), authTokenValue);
                throw new BizException(RespCodeEnum.IDENTITY_INFORM_DISACCORD.getRespCode(), RespCodeEnum.IDENTITY_INFORM_DISACCORD.getRespDesc());
            }
            //设置用户支付密码（password) 区分移动收银台和WEB收银台
            String passwordOffset;
            SafeKeyBoardService safeKeyBoardService = new SafeKeyBoardServiceImpl();
            PasswordInfo passwordInfo = new PasswordInfo(userInfo.getTransPasswordSalt(), PinTypeEnum.DIGITAL, resetPayPasswdRequest.getPassword());
            if (OpmsParamConstant.OPMS_WEB.equals(resetPayPasswdRequest.getHeader().getChanlId())) {
                passwordOffset = safeKeyBoardService.encryptPassword(instId, null, passwordInfo, null);
                if (null == passwordOffset) {
                    rglog.error("设置用户支付密码失败!");
                    throw new BizException(RespCodeEnum.USER_SET_PASSWORD_ERROR.getRespCode(), RespCodeEnum.USER_SET_PASSWORD_ERROR.getRespDesc());
                }
            } else {
                rglog.info("H5收银台:<{}>发起的设置支付密码...", resetPayPasswdRequest.getHeader().getChanlId());
                passwordOffset = safeKeyBoardService.encryptPassword(instId, null, passwordInfo, null);
                if (null == passwordOffset) {
                    rglog.error("设置用户支付密码失败!");
                    throw new BizException(RespCodeEnum.USER_SET_PASSWORD_ERROR.getRespCode(), RespCodeEnum.USER_SET_PASSWORD_ERROR.getRespDesc());
                }
            }
            //验证通过后，删除用户会话中的身份认证流水号
            userService.removeUserSessionValue(UserSessionConstant.IDENTITY_VERIFY_SEQ_NUM);
            //更新用户支付密码（TRANS_PASSWORD)
            userInfo.setTransPassword(passwordOffset);
            boolean modifyFlag = userService.updateUserInfo(userInfo);
            if (!modifyFlag) {
                rglog.info("更新收银台用户信息表用户支付密码失败，instId:<{}>,userId<{}>", instId, userId);
                throw new BizException(RespCodeEnum.USER_SET_PASSWORD_ERROR.getRespCode(), RespCodeEnum.USER_SET_PASSWORD_ERROR.getRespDesc());
            }
            rglog.debug("设置收银台用户信息表用户支付密码成功,instId:<{}>,userId:<{}>", instId, userId);
            //设置响应
            bizResponse.setRspSysId(AppParamConstant.SYS_ID);
            bizResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
            bizResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
            return bizResponse;
        }
        //交易类别 02-密码重置
        else if ("02".equals(txnMode)) {
            //检测上送的手机号和用户的签约手机号是否一致
            if (!userInfo.getMobileNo().equals(resetPayPasswdRequest.getPhoneNo())) {
                rglog.info("上送手机号和用户签约手机号不一致，userMobile:<{}>, reqeustMobile:<{}>",
                        userInfo.getMobileNo(), resetPayPasswdRequest.getPhoneNo());
                throw new BizException(RespCodeEnum.MOBILE_DIFERENT.getRespCode(), RespCodeEnum.MOBILE_DIFERENT.getRespDesc());
            }
            //校验验证码流水号字段，根据session获取会话对象数据，从session对象获取authToken无缓存数据则验证失败；有缓存数据验证通过。验证通过后，设置value为空
            String authTokenValue = userService.getUserSessionValue(UserSessionConstant.IDENTITY_VERIFY_SEQ_NUM);
            if (null == authTokenValue || !authTokenValue.equals(resetPayPasswdRequest.getAuthToken())) {
                rglog.info("授权信息不存在或授权信息不正确，sessionAuthToken:<{}>,requestAuthToken:<{}>", authTokenValue, resetPayPasswdRequest.getAuthToken());
                throw new BizException(RespCodeEnum.IDENTITY_INFORM_DISACCORD.getRespCode(), RespCodeEnum.IDENTITY_INFORM_DISACCORD.getRespDesc());
            }
            //查询用户签约信息表（T_P_SIGN_ACCT_INFO）获取身份验证交易结果状态
            SignAcctInfoMapper signAcctInfoMapper = new SignAcctInfoMapperImpl();
            //查询用户当前签约主体下所有的签约信息
            List<SignAcctInfo> signAcctInfos = signAcctInfoMapper.selectSignAcctInfoBySignTyUserId(instId, userId, signInst);
            if (signAcctInfos != null) {
                //过滤签约状态为正常和本账号的签约信息
                signAcctInfos = signAcctInfos.stream().filter(item -> AppParamConstant.YES.equals(item.getSignStatus())
                        && resetPayPasswdRequest.getPayAcctNo().equals(item.getSignAcctNo())).collect(Collectors.toList());
            }
            if (null == signAcctInfos || signAcctInfos.isEmpty()) {
                rglog.info("用户不存在签约信息，instId:<{}>,signInst:<{}>,signAcctNo:<{}>", instId, signInst, payAcctNo);
                throw new BizException(RespCodeEnum.GET_SIGN_INFO_ERROR.getRespCode(), RespCodeEnum.GET_SIGN_INFO_ERROR.getRespDesc());
            }
            //校验证件号码
            SignAcctInfo signAcctInfo = signAcctInfos.get(0);
            if (signAcctInfo.getCertType().equals(resetPayPasswdRequest.getCertType()) && !signAcctInfo.getCertNo().equals(resetPayPasswdRequest.getCertNo())) {
                rglog.info("用户证件信息不匹配,exitCertType:<{}>,exitCertNo:<{}>,reqCertType:<{}>,reqCertNo:<{}>",
                        signAcctInfo.getCertType(), signAcctInfo.getCertNo(), resetPayPasswdRequest.getCertType(), resetPayPasswdRequest.getCertNo());
                throw new BizException(RespCodeEnum.USER_INFO_MISMATCH.getRespCode(), RespCodeEnum.USER_INFO_MISMATCH.getRespDesc());
            }
            //设置用户支付密码（password)
            String passwordOffset;
            SafeKeyBoardService safeKeyBoardService = new SafeKeyBoardServiceImpl();
            PasswordInfo passwordInfo = new PasswordInfo(userInfo.getTransPasswordSalt(), PinTypeEnum.DIGITAL, resetPayPasswdRequest.getPassword());
            if (OpmsParamConstant.OPMS_WEB.equals(resetPayPasswdRequest.getHeader().getChanlId())) {
                rglog.info("WEB收银台:<{}>发起的设置支付密码...", resetPayPasswdRequest.getHeader().getChanlId());
                passwordOffset = safeKeyBoardService.encryptPassword(instId, null, passwordInfo, null);
                if (null == passwordOffset) {
                    rglog.error("设置用户支付密码失败!");
                    throw new BizException(RespCodeEnum.USER_SET_PASSWORD_ERROR.getRespCode(), RespCodeEnum.USER_SET_PASSWORD_ERROR.getRespDesc());
                }
            } else {
                rglog.info("H5收银台:<{}>发起的设置支付密码...", resetPayPasswdRequest.getHeader().getChanlId());
                passwordOffset = safeKeyBoardService.encryptPassword(instId, null, passwordInfo, null);
                if (null == passwordOffset) {
                    rglog.error("设置用户支付密码失败!");
                    throw new BizException(RespCodeEnum.USER_SET_PASSWORD_ERROR.getRespCode(), RespCodeEnum.USER_SET_PASSWORD_ERROR.getRespDesc());
                }
            }
            //验证通过后，设置value为空
            userService.removeUserSessionValue(UserSessionConstant.IDENTITY_VERIFY_SEQ_NUM);
            //更新用户支付密码（TRANS_PASSWORD)
            userInfo.setTransPassword(passwordOffset);
            boolean modifyFlag = userService.updateUserInfo(userInfo);
            if (!modifyFlag) {
                rglog.info("更新收银台用户信息表用户支付密码失败，instId:<{}>,userId<{}>", instId, userId);
                throw new BizException(RespCodeEnum.USER_SET_PASSWORD_ERROR.getRespCode(), RespCodeEnum.USER_SET_PASSWORD_ERROR.getRespDesc());
            }
            rglog.debug("重置收银台用户信息表用户支付密码成功,instId:<{}>,userId:<{}>", instId, userId);
            //设置响应
            bizResponse.setRspSysId(AppParamConstant.SYS_ID);
            bizResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
            bizResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
            return bizResponse;
        } else {
            rglog.info("无法识别的交易类别,txnMode:<{}>", txnMode);
            throw new BizException(RespCodeEnum.NOT_SURP_TRANS_TYPE_ERROR.getRespCode(), RespCodeEnum.NOT_SURP_TRANS_TYPE_ERROR.getRespDesc());
        }
    }

    @Override
    protected void bizAfterCust(Object response) throws Exception {
        BizResponse bizResponse = (BizResponse) response;
        ResetPayPasswdResponse resetPayPasswdResponse = (ResetPayPasswdResponse) bizResponse.getResult();
        ConvertUtil.convertInput(resetPayPasswdResponse);
    }
}
